import type { Push, Join } from "../array";
import { Or, And3 } from "../common";
import { IsEqual, Compare, IntAddSingle } from "../number";

/**
 * 可以转换成字符串的类型
 */
export type CanStringified =
  | string
  | number
  | bigint
  | boolean
  | null
  | undefined;

/**
 * #### 将支持的类型转换成字符串
 * @example
 * ```ts
 * type a = Stringify<'a'> // 'a'
 * type b = Stringify<1> // '1'
 * ```
 */
export type Stringify<T extends CanStringified> = `${T}`;

/**
 * #### 获取模板字符串类型中的字符
 * @example
 * ```ts
 * type a = GetChars<'a'> // 'a'
 * type b = GetChars<'ab'> // 'a'|'b'
 * type c = GetChars<'abc'> // 'a'|'b'|'c'
 * type d = GetChars<''> // never
 * ```
 */
export type GetChars<S> = GetCharsHelper<S, never>;

/**
 * #### 获取字符串的长度
 * @category String
 * @example
 * ```ts
 * type a = StrLen<'a'> // 1
 * type b = StrLen<'ab'> // 2
 * type c = StrLen<'abc'> // 3
 * type d = StrLen<''> // 0
 * ```
 */
export type StrLen<
  S extends string,
  CountArr extends unknown[] = []
> = S extends `${string}${infer Rest}`
  ? StrLen<Rest, [...CountArr, unknown]>
  : CountArr["length"];

/**
 * #### 反转字符串
 * @category String
 * @example
 * ```ts
 * type a = Reverse<'a'> // 'a'
 * type b = Reverse<'ab'> // 'ba'
 * type c = Reverse<'abc'> // 'cba'
 * type d = Reverse<''> // ''
 * ```
 */
export type Reverse<
  S extends string,
  Result extends string = ""
> = S extends `${infer F}${infer R}` ? Reverse<R, `${F}${Result}`> : Result;

/**
 * 以 尾递归 tail-recursive 的方式优化 GetChars，不导出为工具类型
 */
type GetCharsHelper<S, Acc> = S extends `${infer F}${infer R}`
  ? GetCharsHelper<R, F | Acc>
  : Acc;

type SplitHelper<
  S extends string,
  SplitStr extends string = "",
  T extends string[] = []
> = S extends `${infer Char}${SplitStr}${infer Rest}`
  ? SplitHelper<Rest, SplitStr, Push<T, Char>>
  : S extends string
  ? S extends ""
    ? T
    : Push<T, S>
  : never;

/**
 * #### 将字符串分割成数组
 * @category String
 * @example
 * ```ts
 * type a = Split<'a'> // ['a']
 * type b = Split<'ab'> // ['a', 'b']
 * type c = Split<'abc'> // ['a', 'b', 'c']
 * type d = Split<''> // []
 * ```
 */
export type Split<S extends string, SplitStr extends string = ""> = SplitHelper<
  S,
  SplitStr
>;

/**
 * #### 获取字符串的长度
 */
export type GetStringLength<S extends string> = Split<S>["length"];

/**
 * #### 获取字符串指定位置的字符
 */
export type CharAt<S extends string, I extends number> = Split<S>[I];

/**
 * #### 拼接两个字符串
 */
export type Concat<S1 extends string, S2 extends string> = `${S1}${S2}`;

/**
 * #### 判断字符串是否包含指定子字符串
 */
export type Includes<
  S1 extends String,
  S2 extends string
> = S1 extends `${infer _F}${S2}${infer _R}` ? true : false;

/**
 * #### 判断字符串是否以指定子字符串开头
 */
export type StartsWith<
  S1 extends String,
  S2 extends string
> = S1 extends `${S2}${infer _R}` ? true : false;

/**
 * #### 判断字符串是否以指定子字符串结尾
 */
export type EndsWith<
  S1 extends String,
  S2 extends string
> = S1 extends `${infer _F}${S2}` ? true : false;

/**
 * #### 替换字符串中的指定子字符串
 */
export type Replace<
  S extends string,
  From extends string,
  To extends string
> = S extends `${infer Prefix}${From}${infer Suffix}`
  ? `${Prefix}${To}${Suffix}`
  : S;

/**
 * #### 替换字符串中的所有指定子字符串
 * #### 注意：这个工具类型会一直递归，直到字符串中不再包含指定的子字符串为止
 * @category String
 * @example
 * ```ts
 * type a = ReplaceAll<'abcabc', 'a', 'd'> // 'dbcdbc'
 * ```
 */
export type ReplaceAll<
  S extends string,
  MatchStr extends string,
  ReplaceStr extends string
> = Includes<S, MatchStr> extends true
  ? ReplaceAll<Replace<S, MatchStr, ReplaceStr>, MatchStr, ReplaceStr>
  : S;

type IndexOfHelper<
  S1 extends string,
  S2 extends string,
  Len1 extends number = GetStringLength<S1>,
  Len2 extends number = GetStringLength<S2>
> = Or<Compare<Len1, Len2>, IsEqual<Len1, Len1>> extends true
  ? S1 extends `${infer _F}${S2}${infer _R}`
    ? GetStringLength<_F>
    : -1
  : -1;

/**
 * #### 获取字符串中指定子字符串的位置
 * #### 如果不存在，则返回 -1
 * @category String
 * @example
 * ```ts
 * type a = IndexOf<'abc', 'a'> // 0
 * type b = IndexOf<'abc', 'b'> // 1
 * type c = IndexOf<'abc', 'c'> // 2
 * type d = IndexOf<'abc', 'd'> // -1
 * ```
 */
export type IndexOf<S1 extends string, S2 extends string> = IndexOfHelper<
  S1,
  S2
>;

type LastIndexOfHelper<
  S1 extends string,
  S2 extends string,
  Index extends number = -1 /** 当前从左往右匹配最大的值，匹配不到以后，上一次匹配的索引就是从右往左第一个的索引 */,
  AddOffset extends number = 0 /** 每次从左往右匹配并替换成空串后，下次循序需要累加的值 */
> = S1 extends `${infer Left}${S2}${infer Right}`
  ? LastIndexOfHelper<
      Replace<S1, S2, "">,
      S2,
      IntAddSingle<GetStringLength<Left>, AddOffset>,
      IntAddSingle<AddOffset, GetStringLength<S2>>
    >
  : Index;

export type LastIndexOf<
  S1 extends string,
  S2 extends string
> = LastIndexOfHelper<S1, S2>;

type PadHelper<
  S extends string,
  N extends number = 0,
  FillS extends string = " ",
  IsStart extends boolean = true,
  Len extends number = GetStringLength<S>,
  Offset extends number = Len
> = Compare<N, Len> extends true
  ? IsEqual<N, Offset> extends true
    ? S
    : PadHelper<
        `${IsStart extends true ? FillS : ""}${S}${IsStart extends false
          ? FillS
          : ""}`,
        N,
        FillS,
        IsStart,
        Len,
        IntAddSingle<Offset, 1>
      >
  : S;

/**
 * #### 当字符串不满足给定的长度时，在字符串前面填充使其满足长度
 * @category String
 * @example
 * ```ts
 * type a = PadStart<'a', 3> // '  a'
 * type b = PadStart<'ab', 3> // ' ab'
 * type c = PadStart<'abc', 3> // 'abc'
 * ```
 */
export type PadStart<
  S extends string,
  N extends number,
  FillS extends string = " "
> = PadHelper<S, N, FillS, true>;

/**
 * #### 当字符串不满足给定的长度时，在字符串后面填充使其满足长度
 * @category String
 * @example
 * ```ts
 * type a = PadEnd<'a', 3> // 'a  '
 * type b = PadEnd<'ab', 3> // 'ab '
 * type c = PadEnd<'abc', 3> // 'abc'
 * ```
 */
export type PadEnd<
  S extends string,
  N extends number,
  FillS extends string = " "
> = PadHelper<S, N, FillS, false>;

type RepeatHelper<
  S extends string,
  Times extends number,
  OriginStr extends string = S,
  Offset extends number = 1
> = Times extends 0
  ? ""
  : IsEqual<Times, Offset> extends true
  ? S
  : `${OriginStr}${RepeatHelper<S, Times, OriginStr, IntAddSingle<Offset, 1>>}`;

/**
 * #### 重复字符串指定次数
 * @category String
 * @example
 * ```ts
 * type a = Repeat<'a', 3> // 'aaa'
 * type b = Repeat<'ab', 2> // 'abab'
 * type c = Repeat<'abc', 0> // ''
 * ```
 */
export type Repeat<S extends string, Times extends number> = RepeatHelper<
  S,
  Times
>;

export type TrimLeft<S extends string> = S extends `${
  | " "
  | "\n"
  | "\t"}${infer R}`
  ? TrimLeft<R>
  : S;

export type TrimRight<S extends string> = S extends `${infer L}${
  | " "
  | "\n"
  | "\t"}`
  ? TrimRight<L>
  : S;

export type Trim<S extends string> = TrimLeft<TrimRight<S>>;

type SubStringHelper<
  S extends string,
  Start extends number,
  End extends number,
  Offset extends number = 0,
  Cache extends string[] = []
> = IsEqual<Offset, End> extends true
  ? Join<Cache, "">
  : SubStringHelper<
      S,
      Start,
      End,
      IntAddSingle<Offset, 1>,
      And3<
        Or<Compare<Offset, Start>, IsEqual<Offset, Start>>,
        Or<Compare<End, Offset>, IsEqual<Offset, End>>,
        CharAt<S, Offset> extends string ? true : false
      > extends true
        ? Push<Cache, CharAt<S, Offset>>
        : Cache
    >;

/**
 * #### 截取start（包括）到end（不包括）之间的字符串
 * @category String
 * @example
 * ```ts
 * type a = SubString<'abc', 0, 2> // 'ab'
 * type b = SubString<'abc', 1, 3> // 'bc'
 * type c = SubString<'abc', 0, 4> // 'abc'
 * ```
 */
export type SubString<
  S extends string,
  Start extends number,
  End extends number
> = SubStringHelper<S, Start, End>;

/**
 * #### 截取start（包括）到start+len之间的字符串
 * @category String
 * @example
 * ```ts
 * type a = SubStr<'abc', 0, 2> // 'ab'
 * type b = SubStr<'abc', 1, 2> // 'bc'
 * ```
 */
export type SubStr<
  S extends string,
  Start extends number,
  Len extends number
> = SubStringHelper<S, Start, IntAddSingle<Start, Len>>;

/**
 * #### 将字符串首字母大写
 * @category String
 * @example
 * ```ts
 * type a = Capitalize<'hello world'> // 'Hello world'
 * type b = Capitalize<'hello'> // 'Hello'
 * ```
 */
export type Capitalize<S extends string> = S extends `${infer F} ${infer R}`
  ? `${Uppercase<F>}${R}`
  : S;

/**
 * #### 字符串变成小驼峰
 * @category String
 * @example
 * ```ts
 * type a = CamelCase<'hello_world'> // 'helloWorld'
 * type b = CamelCase<'hello_world_hello'> // 'helloWorldHello'
 * ```
 */
export type CamelCase<S extends string> =
  S extends `${infer Left}_${infer Right}${infer Rest}`
    ? `${Left}${Uppercase<Right>}${CamelCase<Rest>}`
    : S;

/**
 * #### 删除字符串中的某个子串
 * @category String
 * @example
 * ```ts
 * type a = DropSubStr<'abcabc', 'bc'> // 'abca'
 * type b = DropSubStr<'abcabc', 'ab'> // 'cabc'
 * ```
 */
export type DropSubStr<
  S extends string,
  SubStr extends string
> = S extends `${infer Left}${SubStr}${infer Right}`
  ? DropSubStr<`${Left}${Right}`, SubStr>
  : S;

// type test = CharAt<"abcdddd", 3>;
// type indexOf = IndexOf<"abcdddd", "d">;
// type lastIndexOf = LastIndexOf<"23123", "23">;
// type repeat = Repeat<"ab", 2>;
// type subString = SubString<"abc", 1, 3>;
